package com.czkevin.biliwsclient;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;

import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class GuardInfoFetcher implements Iterator<GuardInfoFetcher.FetchedGuard> {

  private static final String URL = "https://api.live.bilibili.com/xlive/app-room/v2/guardTab/topList?roomid=__ROOM__&ruid=__UID__&page=__PAGE__&page_size=20";

  public final long roomId;
  public final long uid;

  public int currentPage = 0;
  public int maxPage = 0;

  public boolean top3Fetched = false;

  public Lock queueLock = new ReentrantLock(false);
  public Queue<FetchedGuard> justFetched = new LinkedTransferQueue<>();

  public GuardInfoFetcher(long roomId, long uid) {
    this.roomId = roomId;
    this.uid = uid;
  }

  @Override
  public boolean hasNext() {
    if(currentPage > 0 && (!justFetched.isEmpty() || currentPage < maxPage)) return true;
    fetchNextPage();
    return !justFetched.isEmpty();
  }

  @Override
  public FetchedGuard next() {
    queueLock.lock();
    try {
      if(!justFetched.isEmpty()) {
        return justFetched.poll();
      }
      fetchNextPage();

      return justFetched.poll();
    } catch (Exception ex) {
      ex.printStackTrace();
      throw new RuntimeException(ex);
    } finally {
      queueLock.unlock();
    }
  }

  private void fetchNextPage() {
    queueLock.lock();
    try {
      currentPage ++;

      String str = HTTPHelper.doGet(
              URL.replace("__ROOM__", Long.toString(roomId))
                      .replace("__UID__", Long.toString(uid))
                      .replace("__PAGE__", Integer.toString(currentPage))
      );

      JSONObject ret = JSON.parseObject(str);
      if(!ret.containsKey("code") || ret.getIntValue("code") != 0) {
        throw new IllegalStateException(String.format("api returned code %s, message: %s", ret.getIntValue("code"), ret.containsKey("message") ? ret.getString("message") : "<null>"));
      }
      JSONObject data = ret.getJSONObject("data");
      JSONObject info = data.getJSONObject("info");
      currentPage = info.getIntValue("now");
      maxPage = info.getIntValue("page");

      if(!top3Fetched) {
        final JSONArray top3 = data.getJSONArray("top3");
        for(int i = 0; i < top3.size(); i++) {
          FetchedGuard f = top3.getObject(i, FetchedGuard.class);
          justFetched.add(f);
        }
      }

      final JSONArray list = data.getJSONArray("list");
      for(int i = 0; i < list.size(); i++) {
        FetchedGuard f = list.getObject(i, FetchedGuard.class);
        justFetched.add(f);
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
      queueLock.unlock();
    }
  }

  @JSONType
  public static class FetchedGuard {
    public long uid;
    public long rank;
    public String username;

    @JSONField(name = "is_alive")
    public int isAlive;

    @JSONField(name = "guard_level")
    public int level;

    @Override
    public String toString() {
      return String.format("%s (level %d, no. #%d, uid #%d, alive=%s)", username, level, rank, uid, isAlive > 0 ? "YES" : "no");
    }
  }

}
